How to Access Environment Variables
Environment variables are a set of dynamic name-value pair set.
They are part of the operating environment in which a process runs and, therefore, they affect the way a running process behave.
Example: PATH used by shell to locate the program whenever no absolute path is provided
From main function
#include <stdio.h>
void main(int argc , char* argv[], char* envp[]){
int i=0;
while(envp[i]!=NULL){
printf("%s\n",envp[i++]);
}
}
envp[] is a NULL terminated array (as argv) and can be only be used by main.
Furthermore, envp[] is a snapshot of the environment variables.
#include <stdio.h>
extern char** environ;
void main(int argc , char* argv[], char* envp[]){
int i=0;
while(environ[i]!=NULL){
printf("%s\n",envp[i++]);
}
}
Now, environ is a global var so it can be used by all the function in such file.
Nevertheless, envrion is a box that contains the actual ENV: if something change inside it, environ "box" will change accordingly.
fork()The child process will automatically inherit its parent process' environment variables.
execve()In this scenario the memory space is overwritten by the data passed through the function. Therefore all the old env variables are lost.
However, by passing to enivron as envp[] args in the function call
execve(const char* filename, char* const argv[], char* const envp[])
we can pass the env variables to the new program.
If we want to:
envp = NULLenvp = newenv[] where newenv should be a NULL terminate array which contain name-value pairs.Environment variables are stored on the stack.
Both envp and environ initially point to the beginning of the environment variables array, (2 in figure).
However, the actual data of the environ variables is placed in another area (1 in figure).
Therefore, when changes are made to the environment vars (such as add, remove vars), there may not be enough space in 1 and 2 to store the new ones. This way result into a reallocation on the heap and only environ, which is a global variable “capture" such change by pointing to the new memory area. On the other hand, envp will not change and, so, it still point to the original area.
Always choose environ over envp
Shell variables are internal variables used by the shell.
We can:
NAME=value)bisca@ubuntu:$ FOO=bar
bisca@ubuntu:$ echo $FOO
bar
unset NAME)bisca@ubuntu:$ unset FOO
bisca@ubuntu:$ echo $FOO
bisca@ubuntu:$
The confusion comes by the fact that shell vars can be env vars and vice-versa.
Indeed, when a shell program starts, it defines a shell var for each of the env vars, using the same name and copying their values.
From now on, any changes on shell variables will not affect env vars and vice-versa.
# /proc/$$/environ -> Print the env vars of the current shell
bisca@ubuntu:$ strings /proc/$$/environ | grep LOGNAME
LOGNAME = bisca # It is an env var
bisca@ubuntu:$ echo LOGNAME
bisca # <- which is a shell var !!!
bisca@ubuntu:$ LOGNAME = zanzi
bisca@ubuntu:$ echo $LOGNAME
zanzi # <- shell var changed
bisca@ubuntu:$ strings /proc/$$/environ | grep LOGNAME
LOGNAME = bisca #Env var is the same, no change
bisca@ubuntu:$ unset LOGNAME
bisca@ubuntu:$ echo $LOGNAME
bisca@ubuntu:$ strings /proc/$$/environ | grep LOGNAME
LOGNAME = bisca #Env var is the same, no change
As we can see in the figure, the shell vars that are passed to the new process as ENV vars are:
unset command, it will not be copied in the new process ENV vars.export commandbisca@ubuntu:$ strings /proc/$$/environ | grep LOGNAME
LOGNAME = bisca # It is an env var
bisca@ubuntu:$ LOGNAME2 = zanzi
bisca@ubuntu: export LOGNAME = rick
# env in shell prompt will create a child process
bisca@ubuntu: env | grep LOGNAME
LOGNAME = bisca
LOGNAME3=rick
bisca@ubuntu:$ unset LOGNAME
bisca@ubuntu: env | grep LOGNAME
LOGNAME3=rick